package com.eastfair.venueservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.base.entity.SuperEntity;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.venueservice.dao.ViolationFineMapper;
import com.eastfair.venueservice.dto.ViolationFineDTO;
import com.eastfair.venueservice.entity.BondManage;
import com.eastfair.venueservice.entity.ViolationFine;
import com.eastfair.venueservice.entity.ViolationRecord;
import com.eastfair.venueservice.enumeration.ViolationFineRefundPathEnum;
import com.eastfair.venueservice.service.BondManageService;
import com.eastfair.venueservice.service.HomeBondManageService;
import com.eastfair.venueservice.service.ViolationFineService;
import com.eastfair.venueservice.service.ViolationRecordService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 违规罚款记录
 * </p>
 *
 * @author dqq
 * @date 2023-04-25
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class ViolationFineServiceImpl extends SuperServiceImpl<ViolationFineMapper, ViolationFine> implements ViolationFineService {

    @Resource
    private HomeBondManageService homeBondManageService;

    @Resource
    private BondManageService bondManageService;

    @Resource
    private ViolationRecordService violationRecordService;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<ViolationFine> modelList) {
        modelList.forEach(s -> s.setIsDeleted(BusinessConstant.YES));
        return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(ViolationFine model) {
        if (model.getIsDeductBond() == null) {
            model.setIsDeductBond(0);
        }
        if (model.getIsRefund() == null) {
            model.setIsRefund(0);
        }
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        return R.successDef();
    }

    @Override
    public List<ViolationFine> listViolationFine(ViolationFineDTO query) {
        log.info("listViolationFine - 查询违规罚款记录, query={}", query);
        QueryWrapper<ViolationFine> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(ViolationFine::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(query.getExhibitorId() != null, ViolationFine::getExhibitorId, query.getViolationId())
                .eq(query.getViolationId() != null, ViolationFine::getViolationId, query.getViolationId())
                .in(query.getViolationRecordIdList() != null && !query.getViolationRecordIdList().isEmpty(), ViolationFine::getViolationId, query.getViolationRecordIdList())
                .eq(StrUtil.isNotBlank(query.getBondOrderNumber()), ViolationFine::getBondOrderNumber, query.getBondOrderNumber())
                .in(query.getBondOrderNumberList() != null && !query.getBondOrderNumberList().isEmpty(), ViolationFine::getBondOrderNumber, query.getBondOrderNumberList())
                .eq(query.getIsDeductBond() != null, ViolationFine::getIsDeductBond, query.getIsDeductBond())
        ;
        return list(queryWrapper);
    }

    @Override
    public List<ViolationFine> listByViolationId(Long violationId) {
        ViolationFineDTO query = new ViolationFineDTO();
        query.setViolationId(violationId);
        return listViolationFine(query);
    }

    @Override
    public List<ViolationFine> listByBondOrderNumber(String bondOrderNumber) {
        ViolationFineDTO query = new ViolationFineDTO();
        query.setBondOrderNumber(bondOrderNumber);
        return listViolationFine(query);
    }

    @Override
    public List<ViolationFine> listByBondOrderNumberList(List<String> bondOrderNumberList) {
        ViolationFineDTO query = new ViolationFineDTO();
        query.setBondOrderNumberList(bondOrderNumberList);
        return listViolationFine(query);
    }

    @Override
    public List<ViolationFine> listByExhibitorId(Long exhibitorId) {
        ViolationFineDTO query = new ViolationFineDTO();
        query.setExhibitorId(exhibitorId);
        return listViolationFine(query);
    }

    @Override
    public List<ViolationFine> listNotDeductByExhibitorId(Long exhibitorId) {
        List<ViolationRecord> violationRecordList = violationRecordService.listByExhibitorId(exhibitorId);
        if (violationRecordList == null || violationRecordList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> violationRecordIdList = violationRecordList
                .stream()
                .map(SuperEntity::getId)
                .collect(Collectors.toList());
        return listNotDeductByViolationIdList(violationRecordIdList);
    }

    @Override
    public List<ViolationFine> listNotDeductByExhibitionManageId(Long exhibitionManageId, Long serviceProviderId) {
        List<ViolationRecord> violationRecordList = violationRecordService.listByExhibitionManageId(exhibitionManageId, serviceProviderId);
        if (violationRecordList == null || violationRecordList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> violationRecordIdList = violationRecordList
                .stream()
                .map(SuperEntity::getId)
                .collect(Collectors.toList());
        return listNotDeductByViolationIdList(violationRecordIdList);
    }

    @Override
    public List<ViolationFine> listNotDeductByViolationIdList(List<Long> violationIdList) {
        ViolationFineDTO query = new ViolationFineDTO();
        query.setViolationRecordIdList(violationIdList);
        query.setIsDeductBond(BusinessConstant.NO);
        return listViolationFine(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveViolationFine(ViolationFineDTO violationFineDTO) {
        log.info("saveViolationFine - 保存违规罚款记录, violationFineDTO={}", violationFineDTO);
        ViolationFine violationFine = BeanUtil.toBean(violationFineDTO, ViolationFine.class);
        return save(violationFine);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveByVenueViolationRecord(ViolationRecord violationRecord) {
        log.info("saveByVenueViolationRecord - 场馆下发的违规记录扣款生成扣款记录,violationRecord={}", violationRecord);
        // 生成违规扣款记录
        ViolationFineDTO violationFineDTO = new ViolationFineDTO();
        violationFineDTO.setViolationId(violationRecord.getId());
        violationFineDTO.setShouldDeductAmount(violationRecord.getShouldPunishAmount());
        violationFineDTO.setActualDeductAmount(violationRecord.getActualPunishAmount());
        // 是否可扣除保证金
        int isDeductBond = bondManageService.canDeductBond(violationRecord.getExhibitionManageId(), violationRecord.getSupervisedId(), violationRecord.getActualPunishAmount());
        violationFineDTO.setIsDeductBond(isDeductBond);
        // 无需扣除保证金，直接保存违规罚款记录
        if (isDeductBond == BusinessConstant.NO) {
            return saveViolationFine(violationFineDTO);
        }
        // 扣除保证金
        BondManage bondManage = bondManageService.deductBondAmount(violationRecord.getExhibitionManageId(), violationRecord.getSupervisedId(), violationRecord.getActualPunishAmount());
        if (bondManage == null) {
            return false;
        }
        // 记录保证金订单编号，并保存违规罚款记录
        violationFineDTO.setBondOrderNumber(bondManage.getOrderNumber());
        return saveViolationFine(violationFineDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveByHomeViolationRecord(ViolationRecord violationRecord) {
        log.info("saveByViolationRecord - 违规记录生成违规罚款记录, violationRecordDTO={}", violationRecord);
        // 生成违规扣款记录
        ViolationFineDTO violationFineDTO = new ViolationFineDTO();
        violationFineDTO.setViolationId(violationRecord.getId());
        violationFineDTO.setShouldDeductAmount(violationRecord.getShouldPunishAmount());
        violationFineDTO.setActualDeductAmount(violationRecord.getActualPunishAmount());
        // 是否可扣除保证金
        int isDeductBond = homeBondManageService.canDeductBond(violationRecord.getExhibitorId(), violationRecord.getActualPunishAmount());
        violationFineDTO.setIsDeductBond(isDeductBond);
        // 无需扣除保证金，直接保存违规罚款记录
        if (isDeductBond == BusinessConstant.NO) {
            return saveViolationFine(violationFineDTO);
        }
        // 扣除保证金
        BondManage bondManage = homeBondManageService.deductBondAmount(violationRecord.getExhibitorId(), violationRecord.getActualPunishAmount());
        if (bondManage == null) {
            return false;
        }
        // 记录保证金订单编号，并保存违规罚款记录
        violationFineDTO.setBondOrderNumber(bondManage.getOrderNumber());
        return saveViolationFine(violationFineDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelByViolationRecord(ViolationRecord violationRecord) {
        log.info("cancelByViolationRecord - 撤销违规记录之后撤销违规罚款记录, violationRecord={}", violationRecord);
        List<ViolationFine> violationFineList = listByViolationId(violationRecord.getId());
        if (violationFineList == null || violationFineList.isEmpty()) {
            return false;
        }
        for (ViolationFine violationFine: violationFineList) {
            // 判断是从保证金扣除，如果是从保证金扣除，则退回到保证金
            if (violationFine.getIsDeductBond() == BusinessConstant.YES && StrUtil.isNotBlank(violationFine.getBondOrderNumber())) {
                bondManageService.refundBondManage(violationFine.getBondOrderNumber(), violationFine.getActualDeductAmount());
            }
        }
        // 删除违规扣款记录
        removeByViolationId(violationRecord.getId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelByBondOrderNumber(String bondOrderNumber) {
        log.info("cancelByBondManage - 取消保证金订单之后撤销违规罚款记录, bondOrderNumber={}", bondOrderNumber);
        List<ViolationFine> list = listByBondOrderNumber(bondOrderNumber);
        if (list == null || list.isEmpty()) {
            return false;
        }
        list.forEach(violationFine -> {
            violationFine.setBondOrderNumber(null);
            updateAllById(violationFine);
        });
        return true;
    }

    @Override
    public boolean cancelByBondOrderNumberList(List<String> bondOrderNumberList) {
        if (bondOrderNumberList == null || bondOrderNumberList.isEmpty()) {
            return false;
        }
        for (String bondOrderNumber: bondOrderNumberList) {
            cancelByBondOrderNumber(bondOrderNumber);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateVenueBondOrderNumber(Long exhibitionManageId, Long serviceProviderId, String bondOrderNumber) {
        log.info("updateVenueBondOrderNumber - 场馆保证金更新违规扣款记录的保证金订单编号, exhibitionManageId={},serviceProviderId={}, bondOrderNumber={}", exhibitionManageId, serviceProviderId, bondOrderNumber);
        List<ViolationFine> violationFineList = listNotDeductByExhibitionManageId(exhibitionManageId, serviceProviderId);
        if (violationFineList == null || violationFineList.isEmpty()) {
            return false;
        }
        return updateBondOrderNumber(violationFineList, bondOrderNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateHomeBondOrderNumber(Long exhibitorId, String bondOrderNumber) {
        log.info("updateHomeBondOrderNumber - 主场保证金更新违规扣款记录的保证金订单编号, exhibitorId={}, bondOrderNumber={}", exhibitorId, bondOrderNumber);
        List<ViolationFine> violationFineList = listNotDeductByExhibitorId(exhibitorId);
        if (violationFineList == null || violationFineList.isEmpty()) {
            return false;
        }
        return updateBondOrderNumber(violationFineList, bondOrderNumber);
    }

    @Override
    public boolean updateBondOrderNumber(List<ViolationFine> violationFineList, String bondOrderNumber) {
        // 更新保证金订单编号，并且计算扣款的总金额
        BigDecimal totalShouldDeductAmount = BigDecimal.ZERO;
        for (ViolationFine violationFine: violationFineList) {
            BigDecimal actualDeductAmount = violationFine.getActualDeductAmount() == null ? BigDecimal.ZERO : violationFine.getActualDeductAmount();
            totalShouldDeductAmount = totalShouldDeductAmount.add(actualDeductAmount);
            violationFine.setBondOrderNumber(bondOrderNumber);
            updateById(violationFine);
        }
        // 扣除保证金订单的金额
        bondManageService.deductBondAmount(bondOrderNumber, totalShouldDeductAmount);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateIsRefund(Long id, ViolationFineRefundPathEnum refundPath) {
        ViolationFine violationFine = getById(id);
        if (violationFine == null) {
            throw BizException.wrap(-1, "违规罚款记录不存在");
        }
        violationFine.setIsRefund(BusinessConstant.YES);
        violationFine.setRefundPath(refundPath);
        return updateById(violationFine);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByViolationId(Long violationId) {
        log.info("removeByViolationId - 违规记录ID移除违规罚款记录, violationId={}", violationId);
        List<ViolationFine> list = listByViolationId(violationId);
        if (list == null || list.isEmpty()) {
            return false;
        }
        return removeByIdsOfLogic(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Long id) {
        ViolationFine violationFine = getById(id);
        if (violationFine == null) {
            throw BizException.wrap(-1, "违规罚款记录不存在");
        }
        List<ViolationFine> list = new ArrayList<>();
        list.add(violationFine);
        return removeByIdsOfLogic(list);
    }
}
